﻿using System;
using System.Collections.Generic;
using System.Linq;
using ValidationEngine.Commons.Interfaces;

namespace ValidationEngine.Commons
{
    /// <summary>
    /// Stores validator apply method results
    /// </summary>
    public class ValidationInfo : IValidationInfo
    {
        #region Members
        private List<string> _errors = new List<string>();
        private List<string> _warnings = new List<string>();
        private List<string> _infos = new List<string>();
        private Dictionary<string, IValidationInfo> _conditionals = new Dictionary<string, IValidationInfo>();
        #endregion

        #region Properties
        public string ErrorText { get { return GetAgregatedString(_errors); } }
        public string WarningText { get { return GetAgregatedString(_warnings); } }
        public string InfoText { get { return GetAgregatedString(_infos); } }
        public bool IsValid { get { return _errors.Count == 0; } }
        public Dictionary<string, IValidationInfo> RelativesInfo { get { return _conditionals; } }
        #endregion

        #region Public methods
        public void Add(IValidationInfo validationResult)
        {
            var vr = (ValidationInfo)validationResult;
            MergeLists(_errors, vr._errors);
            MergeLists(_warnings, vr._warnings);
            MergeLists(_infos, vr._infos);
        }

        public void AddRange(IEnumerable<IValidationInfo> validationResults)
        {
            foreach (var item in validationResults)
            {
                Add(item);
            }
        }

        public void ClearErrors()
        {
            _errors.Clear();
        }

        public void ClearWarnings()
        {
            _warnings.Clear();
        }

        public void ClearInfos()
        {
            _infos.Clear();
        }

        public void Clear()
        {
            ClearErrors();
            ClearInfos();
            ClearWarnings();
        }

        public void AddError(string text)
        {
            if (null != text && !_errors.Contains(text))
            {
                _errors.Add(text);
            }
        }

        public void AddWarning(string text)
        {
            if (null != text && !_warnings.Contains(text))
            {
                _warnings.Add(text);
            }
        }

        public void AddInfo(string text)
        {
            if (null != text && !_infos.Contains(text))
            {
                _infos.Add(text);
            }
        }

        public bool HasWarnings
        {
            get { return IsValid && _warnings.Count > 0; }
        }

        public bool HasInfos
        {
            get { return !HasWarnings && _infos.Count > 0; }
        }

        public void SetError(string text)
        {
            _errors.Clear();
            if (null != text)
            {
                _errors.Add(text);
            }
        }

        public void SetWarning(string text)
        {
            _warnings.Clear();
            if (null != text)
            {
                _warnings.Add(text);
            }
        }

        public void SetInfo(string text)
        {
            _infos.Clear();
            if (null != text)
            {
                _infos.Add(text);
            }
        }
        #endregion

        #region Internal methods
        internal void AddConditionals(Dictionary<string, IValidationInfo> dictionary)
        {
            foreach (var propInfo in dictionary)
            {
                if (!_conditionals.ContainsKey(propInfo.Key))
                {
                    _conditionals.Add(propInfo.Key, propInfo.Value);
                }
                else
                {
                    var conditional = (ValidationInfo)_conditionals[propInfo.Key];
                    var vi = (ValidationInfo)propInfo.Value;
                    conditional._errors.AddRange(vi._errors);
                    conditional._warnings.AddRange(vi._warnings);
                    conditional._infos.AddRange(vi._infos);
                }
            }
        }
        #endregion

        #region Tools
        /// <summary>
        /// Returns one string representation of strings collection
        /// </summary>
        /// <param name="list">Collection</param>
        /// <returns>Agregated string</returns>
        private string GetAgregatedString(List<string> list)
        {
            if (list.Count != 0)
            {
                return list.Aggregate((cur, next) => String.Format("{0}\n{1}", cur, next));
            }
            return null;
        }

        /// <summary>
        /// Merges to lists of strings
        /// </summary>
        /// <param name="baseList">Base list</param>
        /// <param name="newList">New list</param>
        private void MergeLists(List<string> baseList, List<string> newList)
        {
            foreach (var item in newList)
            {
                if (!baseList.Contains(item))
                {
                    baseList.Add(item);
                }
            }
        }
        #endregion
    }
}
